#include "syscall.h"

/* constant number for prices */
#define TICKET_PRICE 12
#define POPCORN_PRICE 5
#define SODA_PRICE 4

/*
#define MAX_CLERK 5
#define MAX_TICKET_TAKER 3
#define MAX_CUSTOMER 100
#define MAX_GROUP 100
*/

#define NUM_TICKET_CLERKS 5
#define NUM_CONCESSION_CLERKS 5
#define NUM_TICKET_TAKERS 3
#define NUM_GROUPS 9
#define CUSTOMERS_PER_GROUP 5
#define NUM_CUSTOMERS NUM_GROUPS * CUSTOMERS_PER_GROUP
#define SEATS 25

/* both for ticket clerks, concession clerks and ticket takers */
typedef enum { C_BUSY, C_READY, C_BREAK } ClerkState;

typedef enum { M_INIT, M_WAITING, M_STARTED, M_FINISHED } MovieState;

/* for allocate id */
int idMutex;
int groupSizes;
int customerID;
int ttID;
int tcID;
int ccID;
int headCustomerID;

int outputLock;

/* for shared resources */
int incomeMutex;
int seatMutex;
int leaveMutex;
int totalIncome;

/* for group commucation
make sure the group move together */
int groupLock[NUM_GROUPS];
int groupCV[NUM_GROUPS];
int hcCV[NUM_GROUPS];
int groupMV;
int customerPopcorn;
int customerSoda;
int customerBathroomNumber;
int customerSeat;
int leaveCount;
int groupBathroomCV[NUM_GROUPS];
int groupBathroomMV;

/* for buy ticket */
int tcLineLock;
int tcLock[NUM_TICKET_CLERKS];
int tcLineCV[NUM_TICKET_CLERKS];
int tcCV[NUM_TICKET_CLERKS];
int tcTicket;
int tcPrice;
int tcLineCount;
int tcIncome;
ClerkState tcState;
int tcBreak;
int tcBreakCV;
int tcBreakTime;

/* for buy food */
int ccLineLock;
int ccLock[NUM_CONCESSION_CLERKS];
int ccLineCV[NUM_CONCESSION_CLERKS];
int ccCV[NUM_CONCESSION_CLERKS];
int ccPopcorn;
int ccSoda;
int ccPrice;
int ccLineCount;
int ccIncome;
ClerkState ccState;
int ccBreak;
int ccBreakCV;
int ccBreakTime;

/* for ticket taker */
int ttLineLock;
int ttLock[NUM_TICKET_TAKERS];
int ttLineCV[NUM_TICKET_TAKERS];
int ttCV[NUM_TICKET_TAKERS];
int ttLineCount;
int ttTicket;
int ttStop;
int ttProcess;
int ttTakenSeat;
int ttTicketTotal;
ClerkState ttState;
int ttBreak;
int ttBreakCV;
int ttBreakTime;

/* for playing the movie */
int customerReadyWatchingMovie;
int movieLock;
int movieCV;
int mtLock;
int mtCV;
MovieState movieState;

/* for lobby */
int lobbyCV;

/* for bathroom */
int bathroomLock;

char buf[1000];
int len = 0;

void stringcopy(char* dest, char* src)
{
	int i = 0;
	
	while(src[i] != 0)
	{
		dest[i] = src[i];
		i++;
	}
	
	dest[i] = 0;
}

void init() {
	int i;
	char name[100];
	
	/* Monitor Variable s */
	groupMV = CreateMonitor("groupMV", 7, NUM_GROUPS);
	customerPopcorn = CreateMonitor("customerPopcorn", 15 ,NUM_CUSTOMERS);
	customerSoda = CreateMonitor("customerSoda", 12, NUM_CUSTOMERS);
	customerBathroomNumber = CreateMonitor("custBathNum", 11, NUM_GROUPS);
	customerSeat = CreateMonitor("customerSeat", 12, NUM_CUSTOMERS);
	groupBathroomMV = CreateMonitor("groupBathroomMV", 15, NUM_GROUPS);
	
	tcID = CreateMonitor("tcID", 4, NUM_TICKET_CLERKS);
	tcTicket = CreateMonitor("tcTicket", 8, NUM_TICKET_CLERKS);
	tcPrice = CreateMonitor("tcPrice", 8, NUM_TICKET_CLERKS);
	tcLineCount = CreateMonitor("tcLineCount", 11, NUM_TICKET_CLERKS);
	tcIncome = CreateMonitor("tcIncome", 8, NUM_TICKET_CLERKS);
	tcState = CreateMonitor("tcState", 7, NUM_TICKET_CLERKS);
	tcBreak = CreateMonitor("tcBreak", 7, NUM_TICKET_CLERKS);
	tcBreakTime = CreateMonitor("tcBreakTime", 11, NUM_TICKET_CLERKS);
	
	ccID = CreateMonitor("ccID", 4, NUM_CONCESSION_CLERKS);
	ccPopcorn = CreateMonitor("ccPopcorn", 9, NUM_CONCESSION_CLERKS);
	ccSoda = CreateMonitor("ccSoda", 6, NUM_CONCESSION_CLERKS);
	ccPrice = CreateMonitor("ccPrice", 8, NUM_CONCESSION_CLERKS);
	ccLineCount = CreateMonitor("ccLineCount", 11, NUM_CONCESSION_CLERKS);
	ccIncome = CreateMonitor("ccIncome", 8, NUM_CONCESSION_CLERKS);
	ccState = CreateMonitor("ccState", 7, NUM_CONCESSION_CLERKS);
	ccBreak = CreateMonitor("ccBreak", 7, NUM_CONCESSION_CLERKS);
	ccBreakTime = CreateMonitor("ccBreakTime", 11, NUM_CONCESSION_CLERKS);

	ttID = CreateMonitor("ttID", 4, NUM_TICKET_TAKERS);
	ttTicket = CreateMonitor("ttTicket", 8, NUM_TICKET_TAKERS);
	ttLineCount = CreateMonitor("ttLineCount", 11, NUM_TICKET_TAKERS);
	ttStop = CreateMonitor("ttStop", 6, NUM_TICKET_TAKERS);
	ttProcess = CreateMonitor("ttProcess", 9, NUM_TICKET_TAKERS);
	ttState = CreateMonitor("ttState", 7, NUM_TICKET_TAKERS);
	ttBreak = CreateMonitor("ttBreak", 7, NUM_TICKET_TAKERS);
	ttBreakTime = CreateMonitor("ttBreakTime", 11, NUM_TICKET_TAKERS);

	/* Monitor Variables */
	customerID = CreateMonitor("customerID", 10, 1);
	headCustomerID = CreateMonitor("headCustomerID", 14, 1);

	totalIncome = CreateMonitor("totalIncome", 11, 1);
	
	leaveCount = CreateMonitor("leaveCount", 10, 1);
	ttTakenSeat = CreateMonitor("ttTakenSeat", 11, 1);
	ttTicketTotal = CreateMonitor("ttTicketTotal", 12, 1);
	
	customerReadyWatchingMovie = CreateMonitor("customersWatching", 17, 1);
	movieState = CreateMonitor("movieState", 10, 1);
	
	/* Locks */
	idMutex = CreateLock("ID", 2);
	outputLock = CreateLock("Output", 6);

	incomeMutex = CreateLock("Income Mutex", 12);
	seatMutex = CreateLock("Seat Mutex", 10);
	leaveMutex = CreateLock("Leaving Mutex", 13);
	
	tcLineLock = CreateLock("TC Line Lock", 12);
	ccLineLock = CreateLock("CC Line Lock", 12);  
	ttLineLock = CreateLock("TT Line Lock", 12);
	movieLock = CreateLock("Movie Lock", 10);
	mtLock = CreateLock("MT Lock", 7);
	
	bathroomLock = CreateLock("Bathroom Lock", 13);
	
	/* Condition Variables */
	movieCV = CreateCondition("Movie CV", 8);
	mtCV = CreateCondition("MT CV", 5);
	lobbyCV = CreateCondition("Lobby CV", 8);
	tcBreakCV = CreateCondition("TC BREAK CV", 11);
	ccBreakCV = CreateCondition("CC BREAK CV", 11);
	ttBreakCV = CreateCondition("TT BREAK CV", 11);
	
	/* Lock/Condition s */
	for(i = 0; i < NUM_GROUPS; i++) {
		stringcopy(name, "GL");
		name[2] = 1 + i;
		name[3] = 0;
		groupLock[i] = CreateLock(name, 3);
		stringcopy(name, "GCV");
		name[3] = 1 + i;
		name[4] = 0;
		groupCV[i] = CreateCondition(name, 4);
		stringcopy(name, "HCCV");
		name[4] = 1 + i;
		name[5] = 0;
		hcCV[i] = CreateCondition(name, 5);
		stringcopy(name, "BCV");
		name[3] = 1 + i;
		name[4] = 0;
		groupBathroomCV[i] = CreateCondition(name, 4);
	}
	for(i = 0; i < NUM_TICKET_CLERKS; i++) {
		stringcopy(name, "TCL");
		name[3] = 1 + i;
		name[4] = 0;
		tcLock[i] = CreateLock(name, 4);
		stringcopy(name, "TCLineCV");
		name[8] = 1 + i;
		name[9] = 0;
		tcLineCV[i] = CreateCondition(name, 9);
		stringcopy(name, "TCCV");
		name[4] = 1 + i;
		name[5] = 0;
		tcCV[i] = CreateCondition(name, 5);
	}
	for(i = 0; i < NUM_CONCESSION_CLERKS; i++) {
		stringcopy(name, "CCL");
		name[3] = 1 + i;
		name[4] = 0;
		ccLock[i] = CreateLock(name, 4);
		stringcopy(name, "CCLineCV");
		name[8] = 1 + i;
		name[9] = 0;
		ccLineCV[i] = CreateCondition(name, 9);
		stringcopy(name, "CCCV");
		name[4] = 1 + i;
		name[5] = 0;
		ccCV[i] = CreateCondition(name, 5);
	}
	for(i = 0; i < NUM_TICKET_TAKERS; i++) {
		stringcopy(name, "TTL");
		name[3] = 1 + i;
		name[4] = 0;
		ttLock[i] = CreateLock(name, 4);
		stringcopy(name, "TTLineCV");
		name[8] = 1 + i;
		name[9] = 0;
		ttLineCV[i] = CreateCondition(name, 9);
		stringcopy(name, "TTCV");
		name[4] = 1 + i;
		name[5] = 0;
		ttCV[i] = CreateCondition(name, 5);
	}
}

void print(int x) {
	int num = 1;
	int t = x/10;
	int i;
	char a[11];
	while (t) {
		num++;
		t /= 10;
	}
	for(i = 1; i <= num; i++) {
		a[num-i] = (x%10) + '0';
		x /= 10;
	}
	for(i = 0; i < num; i++) {
		buf[len++] = a[i];
	}
	/* Write(a, num, ConsoleOutput); */
}

void prints(char *a) {
	int i;
	for(i = 0; a[i]; i++)
		buf[len++] = a[i];
	if (buf[len-1] == '\n') {
		Write(buf,len,ConsoleOutput);
		len = 0;
	}
}

void newLine() {
	Write("\n", 1, ConsoleOutput);
}

void space() {
	Write(" ", 1, ConsoleOutput);
}

int str2int(char b[]) {
	int i;
	int sum = 0;
	for(i = 0; ; i++) {
		if (b[i] < '0' || b[i] > '9') break;
		sum = sum * 10 + b[i]-'0';
	}
	return sum;
}